<?php
namespace Common\Model;
use Think\Model;
class McacheModel extends Model {
	protected $optimizationtables;
	protected $defaultcachetime = 30;
	protected $maxversion = 100000;
	protected function _initialize() {
		parent::_initialize();
		$this->optimizationtables = array(
			"mb_activeextra"	=> array ("pk" => "linkid" ),
			"mb_ad"				=> array ("pk" => "id" ),
			"mb_address"		=> array ("pk" => "address_id" ),
			"mb_area"			=> array ("pk" => "id" ),
			"mb_artcate"		=> array ("pk" => "id" ),
			"mb_article"		=> array ("pk" => "id" ),
			"mb_artmount"		=> array ("pk" => "id" ),
			"mb_attention"		=> array ("pk" => "id" ),
			"mb_badword"		=> array ("pk" => "id" ),
			"mb_category"		=> array ("pk" => "id" ),
			"mb_ccomment"		=> array ("pk" => "id" ),
			"mb_ccommentreplay"	=> array ("pk" => "id" ),
			"mb_citem"			=> array ("pk" => "id" ),
			"mb_cjilu"			=> array ("pk" => "id" ),
			"mb_coinscheck"		=> array ("pk" => "id" ),
			"mb_coinsconfig"	=> array ("pk" => "id" ),
			"mb_comment"		=> array ("pk" => "id" ),
			"mb_contry"			=> array ("pk" => "id" ),
			"mb_contrytotransit"=> array ("pk" => "id" ),
			"mb_copper2matter"	=> array ("pk" => "id" ),
			"mb_copperorder"	=> array ("pk" => "id" ),
			"mb_coupon"			=> array ("pk" => "id" ),
			"mb_cpstype"		=> array ("pk" => "id" ),
			"mb_cpsurl"			=> array ("pk" => "id" ),
			"mb_currency"		=> array ("pk" => "id" ),
			"mb_dconfig"		=> array ("pk" => "id" ),
			"mb_favorite"		=> array ("pk" => "id" ),
			"mb_fcommit"		=> array ("pk" => "id" ),
			"mb_jubao"			=> array ("pk" => "id" ),
			"mb_link" 			=> array ("pk" => "id", "ignore" => array ("hit", "showcount" ) ),
			"mb_linkindex" 		=> array ("pk" => "id", "ignore" => array ("hit", "showcount" ) ),
			"mb_linksubsite"	=> array ("pk" => "linkid" ),
			"mb_linktolink"		=> array ("pk" => "id" ),
			"mb_linkwh"			=> array ("pk" => "id" ),
			"mb_mallcomment"	=> array ("pk" => "id" ),
			"mb_mallcommentreplay"	=> array ("pk" => "id" ),
			"mb_message"		=> array ("pk" => "id" ),
			"mb_miane"			=> array ("pk" => "id" ),
			"mb_page"			=> array ("pk" => "id" ),
			"mb_payment"		=> array ("pk" => "id" ),
			"mb_productextra"	=> array ("pk" => "linkid" ),
			"mb_qqauth"			=> array ("pk" => "openid" ),
			"mb_region"			=> array ("pk" => "id" ),
			"mb_showdan"		=> array ("pk" => "id" ,"ignore" => array ("showcount" ) ),
			"mb_showdantolink"	=> array ("pk" => "id" ),
			"mb_sign"			=> array ("pk" => "id" ),
			"mb_signset"		=> array ("pk" => "id" ),
			"mb_site"			=> array ("pk" => "id" ),
			"mb_sitecate"		=> array ("pk" => "id" ),
			"mb_subsite"		=> array ("pk" => "id" ),
			"mb_tag"			=> array ("pk" => "id" ),
			"mb_tags_data"		=> array ("pk" => "id" ),
			"mb_taobaoauth"		=> array ("pk" => "tbuser_id" ),
			"mb_transitcompany"	=> array ("pk" => "id" ),
			"mb_transitwh"		=> array ("pk" => "id" ),
			"mb_unionshortget"	=> array ("pk" => "shortstr" ),
			"mb_user"			=> array ("pk" => "id" ),
			"mb_userextra"		=> array ("pk" => "id" ),
			"mb_voextra"		=> array ("pk" => "linkid" ),
			"mb_vote"			=> array ("pk" => "id" ),
			"mb_weiboauth"		=> array ("pk" => "uid" ),
			"mb_wh"				=> array ("pk" => "id" ),
			"mb_sysmsg"			=> array ("pk" => "id" ),
		);
	}
	//替代model的add方法，在中途执行删除缓存操作
	public function add($data = '', $options = array(), $replace = false) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::add ( $data, $options, $replace );
		}
		$result = parent::add ( $data, $options, $replace );
		$this->deleteselectcache ();
		//删除id对应的缓存,如果表主键不为自增长，则返该缓存策略有问题，请别设置该表的缓存
		if ($this->optimizationtables [$tablename] ['pk'] == $this->getPk ()) {
			$cachename = $tablename . "_find_" . $result;
			S ( $cachename, null );
		}else{
			$cachepk = $this->optimizationtables [$tablename] ['pk'];
			$addresult = parent::find ( $result );
			$cachename = $tablename . "_find_" . $addresult [$cachepk];
			S ( $cachename, null );
		}
		return $result;
	}
	//替代addall
	public function addAll($dataList, $options = array(), $replace = false) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::addAll ( $dataList, $options, $replace );
		}
		$pk = $this->getPk ();
		//取得插入前最大的pk
		$maxpk = parent::max ( $pk );
		$result = parent::addAll ( $dataList, $options, $replace );
		$this->deleteselectcache ();
		if (false !== $result) {
			if ($this->optimizationtables [$tablename] ['pk'] == $this->getPk ()) {
				$maxpk2 = parent::max ( $pk );
				for($i = $maxpk + 1; $i <= $maxpk2; $i ++) {
					$cachename = $tablename . "_find_" . $i;
					S ( $cachename, null );
				}
			}else{
				$cachepk = $this->optimizationtables [$tablename] ['pk'];
				$maxpk2 = parent::max ( $pk );
				parent::where ( array ($pk => array (array ("gt", $maxpk ), array ("elt", $maxpk2 ) ) ) );
				$addresult = parent::getField ( $cachepk, true );
				foreach ( $addresult as $add ) {
					$cachename = $tablename . "_find_" . $add;
					S ( $cachename, null );
				}
			}
		}
		return $result;
	}
	//先查询缓存，如果有则返回缓存，没有则调用查询
	public function find($options = array()) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::find ( $options );
		}
		if (is_numeric ( $options ) || is_string ( $options )) {
			$pk = $this->getPk();
			$this->options ['where'] = array ($pk => $options );
		} elseif (is_array ( $options )) {
			$this->options = $this->_parseOptions ( $options );
		}
		//处理查询语句为字符串的情况
		if (is_string ( $this->options ['where'] )) {
			$where = strtolower ( $this->options ['where'] );
			$where = explode ( " and ", $where );
			$rwhere = array();
			foreach ($where as $w){
				$w = str_replace ( array ("'", "\"", "`", " " ), array ("", "", "", "" ), $w );
				$w = explode ( "=", $w );
				$rwhere[$w[0]] = $w[1];
			}
			$where = $rwhere;
		}else{
			$where = $this->options ['where'];
		}
		$wherekey = $this->optimizationtables [$tablename] ['pk'];
		$wherevar = $where [$wherekey];
		if (count ( $where ) == 1 && (is_numeric ( $wherevar ) || is_string ( $wherevar ))) {
			//取得缓存
			$cachename = $tablename . "_find_" . $wherevar;
			$cacheresult = S ( $cachename );
			if ($cacheresult) {
				$this->options = array ();
				if ($cacheresult == "HAS_NO_DATA") {
					return null;
				}
				return $cacheresult;
			} else {
				$this->field ( true );
				$result = parent::find ( $options );
				if (! is_null ( $result )) {
					S ( $cachename, $result, $this->defaultcachetime );
				} else {
					S ( $cachename, "HAS_NO_DATA", $this->defaultcachetime );
				}
				return $result;
			}
		} else {
			$cacheoptions = $this->options;
			$this->options['limit'] = 1;
			$cachesql = parent::select ( false );
			$cachesqlmd5 = md5($cachesql);
			$this->options = $cacheoptions;
			$cachename = $tablename . "_select_" . $cachesqlmd5;
			//处理version
			$cacheversion = S ( $tablename . "version" );
			if (empty ( $cacheversion )) {
				$cacheversion = 1;
				S ( $tablename . "version", $cacheversion );
			}
			$cachename .= $cacheversion;
			$cacheresult = S ( $cachename );
			if ($cacheresult) {
				$this->options = array ();
				if ($cacheresult == "HAS_NO_DATA") {
					return null;
				}
				return $cacheresult;
			}
			$result = parent::find ();
			if (! is_null ( $result )) {
				S ( $cachename, $result, $this->defaultcachetime );
			} else {
				S ( $cachename, "HAS_NO_DATA", $this->defaultcachetime );
			}
			return $result;
		}
	}
	public function select($options = array()) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::select ( $options );
		}
		//处理子查询
		if ($options === false) {
			return parent::select ( $options );
		}elseif(is_string($options) || is_numeric($options)){
			// 根据主键查询
            $pk   =  $this->getPk();
            if(strpos($options,',')) {
                $where[$pk]     =  array('IN',$options);
            }else{
                $where[$pk]     =  $options;
            }
            $options['where'] = $where;
		}
		
		if(is_array($options)){
			$this->options = $this->_parseOptions ( $options );
		}
		$cacheoptions = $this->options;
		$cachesql = parent::select ( false );
		$this->options = $cacheoptions;
		$cachesqlmd5 = md5 ( $cachesql );
		$cachename = $tablename . "_select_" . $cachesqlmd5;
		//处理version
		$cacheversion = S ( $tablename . "version" );
		if (empty ( $cacheversion )) {
			$cacheversion = 1;
			S ( $tablename . "version",$cacheversion );
		}
		$cachename .= $cacheversion;
		$cacheresult = S ( $cachename );
		if ($cacheresult) {
			//为不影响以后的查询，重置查询条件
			$this->options = array ();
			//返回数据，处理没有数据的清空
			if ($cacheresult == "HAS_NO_DATA") {
				return null;
			}
			return $cacheresult;
		}
		$result = parent::select ();
		if (! is_null ( $result )) {
			S ( $cachename, $result, $this->defaultcachetime );
		} else {
			S ( $cachename, "HAS_NO_DATA", $this->defaultcachetime );
		}
		return $result;
	}
	//调用不带缓存的查询
	public function mdbselect($options = array()) {
		return parent::select ( $options );
	}
	public function save($data = '', $options = array ()) {
		//如果保存的数据为空，则该数据以对象数据为数据		
		if (empty ( $data ) && ! empty ( $this->data )) {
			$data = $this->data;
		}
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::save ( $data, $options );
		}
		$cacheoptions = $this->options;
		$result = parent::save ( $data, $options );
		$this->options = $cacheoptions;
		//如过保存的数据中有主键则修改条件为主键更新
		foreach ( $data as $key => $v ) {
			if ($key == $this->getPk ()) {
				$options['where'] = array ($key => $v );
			}
		}
		$this->options = $this->_parseOptions ( $options );
		//处理where为字符串的情况
		$where = $this->options ['where'];
		//为不影响以后的查询，重置查询条件
		$this->options = array();
		if (is_string ( $where )) {
			$where = strtolower ( $where );
			$where = explode ( " and ", $where );
			$rwhere = array();
			foreach ($where as $w){
				$w = str_replace ( array ("'", "\"", "`", " " ), array ("", "", "", "" ), $w );
				$w = explode ( "=", $w );
				$rwhere[$w[0]] = $w[1];
			}
			$where = $rwhere;
		}
		//如果更新的字段为忽略的字段，则不删除系统缓存。
		$ignore = true;
		if (isset ( $this->optimizationtables [$tablename] ['ignore'] )) {
			foreach ( $data as $key => $v ) {
				if (! in_array ( $key, $this->optimizationtables [$tablename] ['ignore'] ) && $key != $this->getPk ()) {
					$ignore = false;
					break;
				}
			}
		} else {
			$ignore = false;
		}
		if (! $ignore) {
			//清楚缓存的时候，如果存在主键，删除主键对应的缓存，清楚表对应select缓存
			$isiddelete = false;
			foreach ( $where as $key => $v ) {
				if ($this->optimizationtables [$tablename] ['pk'] == $key) {
					$isiddelete = true;
				}
			}
			$saveoptionspk = $where [$this->optimizationtables [$tablename] ['pk']];
			if ($isiddelete && (is_numeric ( $saveoptionspk ) || is_string ( $saveoptionspk ))) {
				$this->deleteidcache ( $saveoptionspk );
				$this->deleteselectcache ();
			} else {
				$this->deleteselectcache ();
			}
		}
		return $result;
	}
	public function getField($field, $sepa = null) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::getField ( $field, $sepa = $sepa );
		}
		$cacheoptions = $this->options;
		$this->options ['field'] = $field;
		$field = trim ( $field );
		if(strpos($field,',')) {
			$this->options ['limit'] = is_numeric ( $sepa ) ? $sepa : '';
		}else{
			if($sepa !== true){
				$this->options ['limit'] = is_numeric ( $sepa ) ? $sepa : 1;
			}
		}
		$cachesql = $this->select ( false );
		$this->options = $cacheoptions;
		$cachesqlmd5 = md5 ( $cachesql );
		$cachename = $tablename . "_select_" . $cachesqlmd5;
		//处理version
		$cacheversion = S ( $tablename . "version" );
		if (empty ( $cacheversion )) {
			$cacheversion = 1;
			S ( $tablename . "version",$cacheversion );
		}
		$cachename .= $cacheversion;
		$cacheresult = S ( $cachename );
		if ($cacheresult) {
			//为不影响以后的查询，重置查询条件
			$this->options = array ();
			//返回数据，处理没有数据的清空
			if ($cacheresult == "HAS_NO_DATA") {
				return null;
			}
			return $cacheresult;
		}
		$result = parent::getField ( $field, $sepa );
		if (! is_null ( $result )) {
			S ( $cachename, $result, $this->defaultcachetime );
		} else {
			S ( $cachename, "HAS_NO_DATA", $this->defaultcachetime );
		}
		return $result;
	}
	public function delete($options = array()) {
		$tablename = $this->getTableName ();
		if (! isset ( $this->optimizationtables [$tablename] )) {
			return parent::delete ( $options );
		}
		$objectoption = $this->options;
		$result =  parent::delete ( $options );
		$this->deleteselectcache();
		//删除find里面的结果
		$where = $objectoption['where'];
		if(is_numeric($options)  || is_string($options)) {
            // 根据主键删除记录
            $pk   =  $this->getPk();
            if(strpos($options,',')) {
                $where[$pk]     =  array('IN', $options);
            }else{
                $where[$pk]     =  $options;
            }
        } elseif (is_array ( $options )) {
        	$this->options = $objectoption;
        	$cacheoption = $this->_parseOptions ( $options );
			$where = $cacheoption['where'];
		}
		//处理where为字符串的情况
		if (is_string ( $where )) {
			$where = strtolower ( $where );
			$where = explode ( " and ", $where );
			$rwhere = array();
			foreach ($where as $w){
				$w = str_replace ( array ("'", "\"", "`", " " ), array ("", "", "", "" ), $w );
				$w = explode ( "=", $w );
				$rwhere[$w[0]] = $w[1];
			}
			$where = $rwhere;
		}
		foreach ( $where as $k => $v ) {
			if ($k == $this->optimizationtables [$tablename] ['pk']) {
				$idarray = array ();
				if (is_array ( $v ) && strtolower ( $v [0] ) == "in") {
					if (is_string ( $v [1] ) || is_numeric ( $v [1] )) {
						if (strpos ( $v [1], ',' )) {
							$idarray = explode ( ",", $v [1] );
						} else {
							$idarray = array ($v [1] );
						}
					} elseif (is_array ( $v [1] )) {
						$idarray = $v [1];
					}
				}else{
					$idarray = array ($v );
				}
				foreach ( $idarray as $id ) {
					$this->deleteidcache ( $id );
				}
			}
		}
		//删除in里面的结果
		return $result;
	}
	private function deleteselectcache() {
		$tablename = $this->getTableName ();
		$tableversion = S ( $tablename . "version" );
		if ($tableversion && $tableversion < $this->maxversion) {
			$tableversion += 1;
		} else {
			$tableversion == 1;
		}
		S ( $tablename . "version", $tableversion );
	}
	private function deleteidcache($id) {
		$tablename = $this->getTableName ();
		$cachename = $tablename . "_find_" . $id;
		S ( $cachename, null );
	}
	
	
}